import java.awt.*;
import java.awt.event.*;
import javax.swing.*; 
import java.util.*;

@SuppressWarnings("serial")

public class priority_queue2 extends JFrame{
	
	private JLabel ExplanationLabel1;//each of these just explain something on the gui
	private JLabel ExplanationLabel2;
	private JLabel ExplanationLabel3;
	private JLabel ExplanationLabel4;
	private JLabel ExplanationLabel5;
	private JLabel ExplanationLabel6;
	private JLabel ExplanationLabel7;
	private JLabel ExplanationLabel8;
	private JLabel ExplanationLabel9;
	private JLabel view_next_eventpri;//rest are labels that change depending on certain actions
	private JLabel view_next_eventinf;
	private JLabel abc;
	private JLabel nprinum;
	private JLabel nname;
	private JLabel n_event;
	private JLabel blankspace;//blank space to spread out buttons and stuff on gui
	private JLabel blankspace1;//blank space that i used to change into code at times
	private JLabel blankspace2;
	private JLabel blankspace3;
	private JTextField log;//where the log string is placed
	private JButton StartQueueButton;//starts the program, creates 40 events
	private JButton view_Action;//randomly generates an action hence executing the first event
	private JButton view_log;//places log string in log text area.  
	private Random randnum;//the random number generator
	private String init_message;//one of the 40 initially generated events
	private String message;
	private String new_a_message;//new message for action a
	private String new_b_message; // new message for action b
	private String event_message;//event created by user
	private String actionlog;//log file that keeps track of events executed and added
	private int top_prinum;//top prioritied number in queue
	private int prinum;//number in priority field box
	private int new_prinum;//number calculated when adding random action
	private int button_command=0;//decided which route yes/no buttons will take
	private int button_command2=0;//decided which route yes/no buttons will take
	private int rnum;     //the random number created
	private int rnum2;      // another random number created
	private JButton addpriority;//allows user to create an event.  
	private JButton AddEvent;//adds the created event to the queue
	private JButton view_next;//views the next event in queue or 
	private JTextField textfield1;
	private JTextField textfield2;
	private JButton YesButton;
	private JButton NoButton;
	PriorityHeap heap = new PriorityHeap();
	
	
	public class PopupWindow1 extends JDialog{		
		public PopupWindow1 (JFrame Frame){
			super(Frame,"Event Execution" ,true);
			setLayout(new FlowLayout());
						
			ExplanationLabel4 = new JLabel("Event is " + heap.currentInfo() + " with priority " + heap.currentPriority() );
			add(ExplanationLabel4);
			
			abc = new JLabel("                    Action Taken?                            ");
			add(abc);
			
			n_event = new JLabel("");
			add(n_event);
							
			view_Action = new JButton("View Action");
			add(view_Action);
						
			nname = new JLabel("");
			add(nname);
			
			nprinum = new JLabel("");
			add(nprinum);
			
			ExplanationLabel6 = new JLabel("View the action");//Would you like to execute a new event?
			add(ExplanationLabel6);
			
			YesButton = new JButton("Yes");
			YesButton.setEnabled(false);
			add(YesButton);
			
			NoButton = new JButton("No");
			NoButton.setEnabled(false);
			add(NoButton);
			
			
			press_yes y = new press_yes();
			YesButton.setBackground(Color.BLUE);
			YesButton.addActionListener(y);
			
			press_no y2 = new press_no();
			NoButton.setBackground(Color.ORANGE);
			NoButton.addActionListener(y2);
			
			view_action_pressed x3 = new view_action_pressed();
			view_Action.addActionListener(x3);
		}	
	}		
	
	public class PriorityHeap {
        public class PriorityEvent {
            public int PR;
            public String INF;

            PriorityEvent(int newPriority, String newInfo) {
                PR = newPriority;
                INF = newInfo;
            }

            public boolean lessThan(PriorityEvent rh) {
                return PR < rh.PR;
            }
        }

        public PriorityHeap() {
            eventHeap = new Vector<PriorityEvent>();
        }

        // Receive a copy of the source heap so we can save it
        // This really should only be used internally, since otherwise we can't guarantee a proper incoming heap
        private PriorityHeap(Vector<PriorityEvent> source) {
            eventHeap = new Vector<PriorityEvent>(source);
        }

        // Build a new instance using our copy constructor and return it
        public PriorityHeap copy() {
            return new PriorityHeap(eventHeap);
        }

        public void enqueue(int newPriority, String newInfo) {
            // Find the beginning index for the deepest leaf's level
            int index = (int)Math.floor(Math.log((double)eventHeap.size() + 1.0)/Math.log(2.0));
            if (index > 0) {
                index = (int)(Math.pow(2.0, (double)index)) - 1;
            }

            // Find the first empty node, if there is one.
            while (index < eventHeap.size() && eventHeap.get(index) != null) {
                ++index;
            }
            
            int parent = index / 2;
            // Verify space exists and add the new event to the end of the array
            eventHeap.ensureCapacity(index + 1);
            eventHeap.add(new PriorityEvent(newPriority, newInfo));
            // While the event is higher priority than its parent in the heap (sift up)
            while (index > 0 && eventHeap.get(index).lessThan(eventHeap.get(parent))) {
                // Swap the new event into its parent
                PriorityEvent temp = eventHeap.get(parent);
                eventHeap.set(parent, eventHeap.get(index));
                // Swap the parent into the old slot
                eventHeap.set(index, temp);
                index = parent;
                parent = index / 2;
            }
        }

        private void heapify(int rootIndex) {
            int left = 2 * rootIndex + 1;
            int right = 2 * rootIndex + 2;
            int least = rootIndex;

            // Check for higher priority left leaf
            if (eventHeap.size() > left && eventHeap.get(left) != null && eventHeap.get(left).lessThan(eventHeap.get(rootIndex))) {
                least = left;
            }
            // Check for higher priority right leaf
            if (eventHeap.size() > right && eventHeap.get(right) != null && eventHeap.get(right).lessThan(eventHeap.get(least))) {
                least = right;
            }
            // Swap higher priority leaf with root if necessary
            if (least != rootIndex) {
                PriorityEvent temp = eventHeap.get(least);
                eventHeap.set(least, eventHeap.get(rootIndex));
                eventHeap.set(rootIndex, temp);
                heapify(least);
            }
        }

        public void dequeue() {
            // Clear the root element
            eventHeap.set(0, null);

            // Find the last element
            int index = eventHeap.size();
            PriorityEvent end = null;
            while (end == null && index > 0) {
                end = eventHeap.get(--index);
            }

            if (end == null) {
                // No valid element sift down, make sure the queue is empty
                eventHeap.clear();
                return;
            } else {
                // Set last element as root, clear its previous spot
                eventHeap.set(0, end);
                eventHeap.set(index, null);
            }

            // Ensure there is a full level below the deepest leaf
            // Avoids out of bounds exceptions
            // Finds the power of 2 needed to achieve currently used depth and double it for potential capacity
            eventHeap.ensureCapacity((int)Math.pow(2.0, 1.0 + Math.ceil(Math.log((double)index)/Math.log(2.0))));
            
            // Sift down the new root element (heapify)
            // "end" becomes "parent"
            heapify(0);
        }

        public boolean isEmpty() {
            return eventHeap.isEmpty();
        }

        // Returns the highest priority value, -1 otherwise
        public int currentPriority() {
            if (!isEmpty()) {
                return eventHeap.firstElement().PR;
            } else {
                return -1;
            }
        }

        // Returns the highest priority info, null otherwise
        public String currentInfo() {
            if (!isEmpty()) {
                return eventHeap.firstElement().INF;
            } else {
                return null;
            }
        }

        public int size(){
            return eventHeap.size();
        }

        private Vector<PriorityEvent> eventHeap;
	}
	
	

	public priority_queue2(){
		
		setLayout(new FlowLayout());
		
		StartQueueButton = new JButton("Start Queue");
		StartQueueButton.setBackground(Color.GREEN);
		add(StartQueueButton);
		
		ExplanationLabel1 = new JLabel("Press \"Start Queue\" to start");
		add(ExplanationLabel1);
		ExplanationLabel2 = new JLabel("adding to the priority queue.");
		add(ExplanationLabel2);
		ExplanationLabel3 = new JLabel("Initially 40 events will be created.");
		add(ExplanationLabel3);
		
		blankspace = new JLabel("                                                                                                ");
		add(blankspace);
		
		addpriority = new JButton("Add Event/Priority");
		addpriority.setBackground(Color.YELLOW);
		addpriority.setEnabled(false);
		add(addpriority);
		
		ExplanationLabel5 = new JLabel("                                              ");//"Enter New Priority             "
		add(ExplanationLabel5);
		
		ExplanationLabel7 = new JLabel("                                              ");//must be more than old priority
		add(ExplanationLabel7);
		
		textfield1 = new JTextField(5);
		textfield1.setBackground(Color.BLACK);
		add(textfield1);		
		
		ExplanationLabel8 = new JLabel("");
		add(ExplanationLabel8);
		
		textfield2 = new JTextField(5);
		textfield2.setBackground(Color.BLACK);
		add(textfield2);		
		
		AddEvent = new JButton("Add New Event");
		AddEvent.setEnabled(false);
		add(AddEvent);
		
		blankspace3 = new JLabel("                                           ");//must be more than old priority
		add(blankspace3);
		blankspace = new JLabel("                                           ");//must be more than old priority
		add(blankspace);
		blankspace = new JLabel("                                           ");//must be more than old priority
		add(blankspace);
		
		blankspace = new JLabel("                                           ");//must be more than old priority
		add(blankspace);
		
		blankspace = new JLabel("                                           ");//must be more than old priority
		add(blankspace);
		
		
		ExplanationLabel9 = new JLabel("                                  ");//must be more than old priority
		add(ExplanationLabel9);
		
		view_next = new JButton("View Next");
		view_next.setEnabled(false);
		add(view_next);
		
		view_next_eventinf = new JLabel("");
		add(view_next_eventinf);
		
		view_next_eventpri = new JLabel("");
		add(view_next_eventpri);
		start_queue_action x = new start_queue_action();
		StartQueueButton.addActionListener(x);
		
		addpriority_action x2 = new addpriority_action();
		addpriority.addActionListener(x2);
		
		view_next_action x4 = new view_next_action();
		view_next.addActionListener(x4);
		
		add_event_action x5 = new add_event_action();
		AddEvent.addActionListener(x5);
		
		blankspace1 = new JLabel("                                           ");//must be more than old priority
		add(blankspace1);
		blankspace = new JLabel("                                           ");//must be more than old priority
		add(blankspace);
		blankspace = new JLabel("                                           ");//must be more than old priority
		add(blankspace);
		
		blankspace = new JLabel("                                           ");//must be more than old priority
		add(blankspace);
		
		blankspace2 = new JLabel("                                           ");//must be more than old priority
		add(blankspace2);
		
		view_log = new JButton("View Your Recent Actions");
		view_log.setEnabled(false);
		add(view_log);
		
		log = new JTextField(30);
		add(log);
		
		viewlogaction x6 = new viewlogaction();
		view_log.addActionListener(x6);		
	}
	
	
	
	public class start_queue_action implements ActionListener { //do after Start Queue Button
		public void actionPerformed(ActionEvent x){
			
			view_log.setEnabled(true);
			actionlog = "40 events added to Queue; ";
			
			StartQueueButton.setEnabled(false);//disables start button from being
            // pressed again.
			for (int z = 1; z < 10; z = z + 1) {
				init_message = "act0" + z;
				randnum = new Random();//creates new random generator
				rnum2 = randnum.nextInt(50)+ 1;//creates a random number from 1 to 50
				heap.enqueue(rnum2, init_message);
				
			}
			for (int h = 10; h < 41; h = h + 1) {
				init_message = "act" + h;
				randnum = new Random();//creates new random generator
				rnum2 = randnum.nextInt(50)+1;//creates a random number from 1 to 50
				heap.enqueue(rnum2, init_message);
			}                                     
			ExplanationLabel1.setText("40 Events were created");
			ExplanationLabel2.setText("They were added the priority queue                                       ");
			ExplanationLabel3.setText("");
			
			PopupWindow1 guipopup = new PopupWindow1(priority_queue2.this);//creates first popup window
			guipopup.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
			guipopup.setSize(250,300);
			guipopup.setLocation(300,400);
			guipopup.setVisible(true);
			return;
		}
	}
	public class press_yes implements ActionListener { 
		public void actionPerformed(ActionEvent y){
			if(button_command2==1){//if this is the second yes
				heap.dequeue();
				if (!heap.isEmpty()){
						actionlog = actionlog + heap.currentInfo() +" executed; ";
				}
				if(heap.isEmpty()){
					ExplanationLabel6.setText("  The Queue is empty.  EXIT THIS WINDOW              ");
					YesButton.setEnabled(false);
					NoButton.setEnabled(false);
					view_next.setEnabled(false);
					return;
				}
				
				ExplanationLabel4.setText("Event is " + heap.currentInfo() + " with priority " + heap.currentPriority());
				abc.setText("Action Taken");
				nname.setText("");
				n_event.setText("");
				nprinum.setText("");
				ExplanationLabel6.setText("View the Action");
				view_Action.setEnabled(true);
				YesButton.setEnabled(false);
				NoButton.setEnabled(false);
				return;
			}
			heap.dequeue();
			if (!heap.isEmpty()){
					actionlog = actionlog + heap.currentInfo() +" executed; ";
			}
			if(heap.isEmpty()){
				return;
			}
			addpriority.setEnabled(true);
			NoButton.setEnabled(false);
			YesButton.setEnabled(false);
			ExplanationLabel6.setText("                EXIT THIS WINDOW              ");
			return;
		}
	}
	
	public class viewlogaction implements ActionListener { 
		public void actionPerformed(ActionEvent x6){
			log.setText(actionlog);
			return;
		}
	}
	
	public class press_no implements ActionListener { 
		public void actionPerformed(ActionEvent y2){
			if (button_command2 == 1){//after selecting no the first time, you will go through this loos the second the time.  
				button_command=1;
				NoButton.setEnabled(false);
				YesButton.setEnabled(false);
				ExplanationLabel6.setText("               EXIT THIS WINDOW                 ");
				ExplanationLabel9.setText("View next label without any new events being generated");
				view_next.setEnabled(true);
				button_command2 = 0;//resets so the first no can come up again next time. 
				return;
			}
			ExplanationLabel6.setText("Would you like to execute the next event?");
			button_command2 = 1;
			return;
		}
	}
	
	public class add_event_action implements ActionListener { 
		public void actionPerformed(ActionEvent x5){
			if(heap.currentPriority() > 200){
				blankspace3.setText("current priority is greater than 200.  Exit the program");
				return;
			}
			event_message = textfield2.getText();
			top_prinum = heap.currentPriority();  
			int messagelength = event_message.length(); //finds length of message
	        if (messagelength != 5){//if the length of the message is no 5
	            textfield2.setBackground(Color.PINK);//changes field box to pink
	            blankspace3.setText("Event must contain 5 Characters!");//prints error
	            return;//exits action of button
	        }
	        textfield2.setBackground(Color.WHITE);
	        try{
	            prinum = (Integer.parseInt(String.valueOf(textfield1.getText())));
	        }//if the priority field box is not a number
	        catch (Exception e) {
	            textfield1.setBackground(Color.PINK);//Error
	            blankspace3.setText("Priority must be an integer between 0 and 200");//prints error
	            return;//exits action of button
	        }
	        if (prinum < top_prinum || prinum > 200){//if prinum is not between 0 and 200
	            textfield1.setBackground(Color.RED);//Error
	            blankspace3.setText("Priority must be an integer between 0 and 200");//Print error
	            return;//exit function
	        }
	        blankspace3.setText("Event added to queue");
	        textfield1.setBackground(Color.WHITE);
	        actionlog = actionlog + event_message+" added; ";
	        AddEvent.setEnabled(false);
	        view_next.setEnabled(true);
	        heap.enqueue(prinum, event_message);
			return;
		}
	}
	
	public class view_next_action implements ActionListener { 
		public void actionPerformed(ActionEvent x4){
			if (button_command == 1){
				if(heap.isEmpty()){
					view_next_eventinf.setText("The Queue is Empty");
					view_next_eventpri.setText("");
					view_next.setEnabled(false);
					return;
				}
				heap.dequeue();
				if (!heap.isEmpty()){
						actionlog = actionlog + heap.currentInfo() +" executed; ";
				}
				if(heap.isEmpty()){
					view_next_eventinf.setText("The Queue is Empty");
					view_next_eventpri.setText("");
					return;
				}
				view_next_eventinf.setText("Next Event: " + heap.currentInfo());
				view_next_eventpri.setText("Next Event Priority: " + heap.currentPriority()); 
				ExplanationLabel9.setText("View next label without any new events being generated");
				return;
			}
			view_next.setEnabled(false);
			//creates the pop up window.  
			PopupWindow1 guipopup = new PopupWindow1(priority_queue2.this);//creates first popup window
			guipopup.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
			guipopup.setSize(250,300);
			guipopup.setLocation(300,400);
			guipopup.setVisible(true);
			return;
		}
	}
	
	
	public class view_action_pressed implements ActionListener { 
		public void actionPerformed(ActionEvent x3){
			button_command2 = 0;
			NoButton.setEnabled(true);
			YesButton.setEnabled(true);
			view_Action.setEnabled(false);
			ExplanationLabel6.setText("Would you like to insert a new event?");
			
			randnum = new Random();//creates new random generator
			rnum = randnum.nextInt(10);//creates a random number from 0 to 9
			message = heap.currentInfo();
			prinum = heap.currentPriority();

			if (rnum < 5){//for random number less than 5 (50% chance of occurrence)
			    abc.setText("Action Taken: a                  ");//changes label so user knows what happened
			    n_event.setText("Action: New Event created");//changes label so user
			                                        //knows what happened
			    new_a_message = "new_a-"+message;
			    actionlog = actionlog + new_a_message+" added; ";
			    nname.setText("New event name: " + new_a_message);
			    new_prinum = prinum + prinum*3;//new priority is given for
			                                    //appropriate event
			    nprinum.setText("New event priority: " + String.valueOf(new_prinum) + "                  ");//prints new priority
			    heap.enqueue(new_prinum, new_a_message);
			}
			if (rnum > 4 && rnum < 8){//for random number between 5 and 7
			                            //(30% chance of occurrence)
			    abc.setText("Action Taken: b                ");//changes label so user knows what happened
			    n_event.setText("New Event created");
			    new_b_message = "new_b-"+message;
			    actionlog = actionlog + new_b_message+" added; ";
			    nname.setText("New event name: " + new_b_message);

			    new_prinum = prinum + prinum*10; //new priority is given for
			                                    //appropriate event
			    nprinum.setText("New event priority: " + String.valueOf(new_prinum));//prints new priority
			    heap.enqueue(new_prinum, new_b_message);
			}
			if (rnum > 7){//for random number more than 8 (20% chance of occurrence)
			    abc.setText("Action Taken: c");//changes label so user knows what happened
			    n_event.setText("Action: No new Event created");
			    nname.setText("");
			    nprinum.setText("");
			}
			return;
		}
	}
	
	public class addpriority_action implements ActionListener { //do after addpriority Button
		public void actionPerformed(ActionEvent x2){
			
			AddEvent.setEnabled(true);
			addpriority.setEnabled(false);
			textfield1.setBackground(Color.WHITE);
			textfield2.setBackground(Color.WHITE);
			ExplanationLabel5.setText("Enter New Priority             ");
			ExplanationLabel7.setText("must be more than old priority");
			ExplanationLabel8.setText("Enter INF (5 Character String)");
			return;
		}
		
		
	}
	public static void main (String args[]){
		priority_queue2 gui = new priority_queue2();
		gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		gui.setVisible(true);
		gui.setSize(400,400);
		return;
	}
}
